package client_test import ( "bytes" "context" "log" "net/http" "testing" "time" "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" "github.com/tendermint/tendermint/abci/example/kvstore" rpchttp "github.com/tendermint/tendermint/rpc/client/http" "github.com/tendermint/tendermint/rpc/coretypes" rpctest "github.com/tendermint/tendermint/rpc/test" ) func TestHTTPSimple(t *testing.T) { ctx, cancel := context.WithCancel(context.Background()) defer cancel() // Start a tendermint node (and kvstore) in the background to test against app := kvstore.NewApplication() conf, err := rpctest.CreateConfig("ExampleHTTP_simple") require.NoError(t, err) _, closer, err := rpctest.StartTendermint(ctx, conf, app, rpctest.SuppressStdout) if err != nil { log.Fatal(err) //nolint:gocritic } defer func() { _ = closer(ctx) }() // Create our RPC client rpcAddr := conf.RPC.ListenAddress c, err := rpchttp.New(rpcAddr) require.NoError(t, err) // Create a transaction k := []byte("name") v := []byte("satoshi") tx := append(k, append([]byte("="), v...)...) // Broadcast the transaction and wait for it to commit (rather use // c.BroadcastTxSync though in production). bres, err := c.BroadcastTxCommit(context.Background(), tx) require.NoError(t, err) if err != nil { log.Fatal(err) } if bres.CheckTx.IsErr() || bres.DeliverTx.IsErr() { log.Fatal("BroadcastTxCommit transaction failed") } // Now try to fetch the value for the key qres, err := c.ABCIQuery(context.Background(), "/key", k) require.NoError(t, err) require.False(t, qres.Response.IsErr(), "ABCIQuery failed") require.True(t, bytes.Equal(qres.Response.Key, k), "returned key does not match queried key") require.True(t, bytes.Equal(qres.Response.Value, v), "returned value does not match sent value [%s]", string(v)) assert.Equal(t, "name=satoshi", string(tx), "sent tx") assert.Equal(t, "name", string(qres.Response.Key), "queried for") assert.Equal(t, "satoshi", string(qres.Response.Value), "got value") } func TestHTTPBatching(t *testing.T) { ctx, cancel := context.WithCancel(context.Background()) defer cancel() // Start a tendermint node (and kvstore) in the background to test against app := kvstore.NewApplication() conf, err := rpctest.CreateConfig("ExampleHTTP_batching") require.NoError(t, err) _, closer, err := rpctest.StartTendermint(ctx, conf, app, rpctest.SuppressStdout) if err != nil { log.Fatal(err) //nolint:gocritic } defer func() { _ = closer(ctx) }() rpcAddr := conf.RPC.ListenAddress c, err := rpchttp.NewWithClient(rpcAddr, http.DefaultClient) require.NoError(t, err) // Create our two transactions k1 := []byte("firstName") v1 := []byte("satoshi") tx1 := append(k1, append([]byte("="), v1...)...) k2 := []byte("lastName") v2 := []byte("nakamoto") tx2 := append(k2, append([]byte("="), v2...)...) txs := [][]byte{tx1, tx2} // Create a new batch batch := c.NewBatch() // Queue up our transactions for _, tx := range txs { // Broadcast the transaction and wait for it to commit (rather use // c.BroadcastTxSync though in production). _, err := batch.BroadcastTxSync(ctx, tx) require.NoError(t, err) } // Send the batch of 2 transactions _, err = batch.Send(ctx) require.NoError(t, err) // wait for the transaction to land, we could poll more for // the transactions to land definitively. require.Eventually(t, func() bool { // Now let's query for the original results as a batch exists := 0 for _, key := range [][]byte{k1, k2} { _, err := batch.ABCIQuery(context.Background(), "/key", key) if err == nil { exists++ } } return exists == 2 }, 10*time.Second, time.Second, ) // Send the 2 queries and keep the results results, err := batch.Send(ctx) require.NoError(t, err) require.Len(t, results, 2) // Each result in the returned list is the deserialized result of each // respective ABCIQuery response for _, result := range results { qr, ok := result.(*coretypes.ResultABCIQuery) require.True(t, ok, "invalid result type from ABCIQuery request") switch string(qr.Response.Key) { case "firstName": require.Equal(t, "satoshi", string(qr.Response.Value)) case "lastName": require.Equal(t, "nakamoto", string(qr.Response.Value)) default: t.Fatalf("encountered unknown key %q", string(qr.Response.Key)) } } }