From 1fbd3739afd280a1d4ba176df667bcb2506f9510 Mon Sep 17 00:00:00 2001
From: sunspirit <167175638+linhpn99@users.noreply.github.com>
Date: Mon, 22 Jul 2024 15:58:24 +0700
Subject: [PATCH 1/2] feat(gnokey): Print out the transaction hash when maketx
executes successfully (#2309)
Relate to https://github.com/gnolang/gno/issues/2303
Contributors' checklist...
- [ ] Added new tests, or not needed, or not feasible
- [ ] Provided an example (e.g. screenshot) to aid review or the PR is
self-explanatory
- [ ] Updated the official documentation or not needed
- [ ] No breaking changes were made, or a `BREAKING CHANGE: xxx` message
was included in the description
- [ ] Added references to related issues and PRs
- [ ] Provided any useful hints for running manual tests
- [ ] Added new benchmarks to [generated
graphs](https://gnoland.github.io/benchmarks), if any. More info
[here](https://github.com/gnolang/gno/blob/master/.benchmarks/README.md).
---
gno.land/cmd/gnoland/testdata/addpkg.txtar | 1 +
gno.land/cmd/gnoland/testdata/addpkg_invalid.txtar | 2 +-
gno.land/cmd/gnoland/testdata/event_callback.txtar | 2 +-
gno.land/cmd/gnoland/testdata/event_defer_callback_loop.txtar | 1 +
gno.land/cmd/gnoland/testdata/event_for_statement.txtar | 3 ++-
gno.land/cmd/gnoland/testdata/event_normal.txtar | 2 ++
gno.land/cmd/gnoland/testdata/run.txtar | 1 +
gno.land/pkg/integration/testdata/adduser.txtar | 1 +
gno.land/pkg/integration/testdata/loadpkg_work.txtar | 1 +
tm2/pkg/crypto/keys/client/broadcast.go | 3 +++
tm2/pkg/crypto/keys/client/maketx.go | 3 +++
11 files changed, 17 insertions(+), 3 deletions(-)
diff --git a/gno.land/cmd/gnoland/testdata/addpkg.txtar b/gno.land/cmd/gnoland/testdata/addpkg.txtar
index e62bce0c59f..6249d2ff7a0 100644
--- a/gno.land/cmd/gnoland/testdata/addpkg.txtar
+++ b/gno.land/cmd/gnoland/testdata/addpkg.txtar
@@ -16,6 +16,7 @@ stdout 'GAS WANTED: 2000000'
stdout 'GAS USED: \d+'
stdout 'HEIGHT: \d+'
stdout 'EVENTS: \[\]'
+stdout 'TX HASH: '
-- hello.gno --
package hello
diff --git a/gno.land/cmd/gnoland/testdata/addpkg_invalid.txtar b/gno.land/cmd/gnoland/testdata/addpkg_invalid.txtar
index 5cfd48bf2ea..bcec784a530 100644
--- a/gno.land/cmd/gnoland/testdata/addpkg_invalid.txtar
+++ b/gno.land/cmd/gnoland/testdata/addpkg_invalid.txtar
@@ -7,7 +7,7 @@ gnoland start
! gnokey maketx addpkg -pkgdir $WORK -pkgpath gno.land/r/foobar/bar -gas-fee 1000000ugnot -gas-wanted 2000000 -broadcast -chainid=tendermint_test test1
# check error message
-! stdout .+
+stdout 'TX HASH: '
stderr 'as string value in return statement'
stderr '"std" imported and not used'
diff --git a/gno.land/cmd/gnoland/testdata/event_callback.txtar b/gno.land/cmd/gnoland/testdata/event_callback.txtar
index 3606cfae81e..86377dfee6b 100644
--- a/gno.land/cmd/gnoland/testdata/event_callback.txtar
+++ b/gno.land/cmd/gnoland/testdata/event_callback.txtar
@@ -10,7 +10,7 @@ stdout 'GAS WANTED: 2000000'
stdout 'GAS USED: [0-9]+'
stdout 'HEIGHT: [0-9]+'
stdout 'EVENTS: \[{\"type\":\"foo\",\"attrs\":\[{\"key\":\"k1\",\"value\":\"v1\"},{\"key\":\"k2\",\"value\":\"v2\"}],\"pkg_path\":\"gno.land\/r\/demo\/cbee\",\"func\":\"subFoo\"},{\"type\":\"bar\",\"attrs\":\[{\"key\":\"bar\",\"value\":\"baz\"}],\"pkg_path\":\"gno.land\/r\/demo\/cbee\",\"func\":\"subBar\"}]'
-
+stdout 'TX HASH: '
-- cbee.gno --
package cbee
diff --git a/gno.land/cmd/gnoland/testdata/event_defer_callback_loop.txtar b/gno.land/cmd/gnoland/testdata/event_defer_callback_loop.txtar
index 2bb572271ad..44388be502d 100644
--- a/gno.land/cmd/gnoland/testdata/event_defer_callback_loop.txtar
+++ b/gno.land/cmd/gnoland/testdata/event_defer_callback_loop.txtar
@@ -10,6 +10,7 @@ stdout 'GAS WANTED: 2000000'
stdout 'GAS USED: [0-9]+'
stdout 'HEIGHT: [0-9]+'
stdout 'EVENTS: \[{\"type\":\"ForLoopEvent\",\"attrs\":\[{\"key\":\"iteration\",\"value\":\"0\"},{\"key\":\"key\",\"value\":\"value\"}\],\"pkg_path\":\"gno.land\/r\/demo\/edcl\",\"func\":\"\"},{\"type\":\"ForLoopEvent\",\"attrs\":\[{\"key\":\"iteration\",\"value\":\"1\"},{\"key\":\"key\",\"value\":\"value\"}\],\"pkg_path\":\"gno.land\/r\/demo\/edcl\",\"func\":\"\"},{\"type\":\"ForLoopEvent\",\"attrs\":\[{\"key\":\"iteration\",\"value\":\"2\"},{\"key\":\"key\",\"value\":\"value\"}\],\"pkg_path\":\"gno.land\/r\/demo\/edcl\",\"func\":\"\"},{\"type\":\"ForLoopCompletionEvent\",\"attrs\":\[{\"key\":\"count\",\"value\":\"3\"}\],\"pkg_path\":\"gno.land\/r\/demo\/edcl\",\"func\":\"forLoopEmitExample\"},{\"type\":\"CallbackEvent\",\"attrs\":\[{\"key\":\"key1\",\"value\":\"value1\"},{\"key\":\"key2\",\"value\":\"value2\"}\],\"pkg_path\":\"gno.land\/r\/demo\/edcl\",\"func\":\"\"},{\"type\":\"CallbackCompletionEvent\",\"attrs\":\[{\"key\":\"key\",\"value\":\"value\"}\],\"pkg_path\":\"gno.land\/r\/demo\/edcl\",\"func\":\"callbackEmitExample\"},{\"type\":\"DeferEvent\",\"attrs\":\[{\"key\":\"key1\",\"value\":\"value1\"},{\"key\":\"key2\",\"value\":\"value2\"}\],\"pkg_path\":\"gno.land\/r\/demo\/edcl\",\"func\":\"deferEmitExample\"}\]'
+stdout 'TX HASH: '
-- edcl.gno --
diff --git a/gno.land/cmd/gnoland/testdata/event_for_statement.txtar b/gno.land/cmd/gnoland/testdata/event_for_statement.txtar
index 63eb26c47d8..be7f501f255 100644
--- a/gno.land/cmd/gnoland/testdata/event_for_statement.txtar
+++ b/gno.land/cmd/gnoland/testdata/event_for_statement.txtar
@@ -10,6 +10,7 @@ stdout 'GAS WANTED: 2000000'
stdout 'GAS USED: [0-9]+'
stdout 'HEIGHT: [0-9]+'
stdout 'EVENTS: \[{\"type\":\"testing\",\"attrs\":\[{\"key\":\"foo\",\"value\":\"bar\"}\],\"pkg_path\":\"gno.land\/r\/demo\/foree\",\"func\":\"Foo\"},{\"type\":\"testing\",\"attrs\":\[{\"key\":\"foo\",\"value\":\"bar\"}\],\"pkg_path\":\"gno.land\/r\/demo\/foree\",\"func\":\"Foo\"},{\"type\":\"testing\",\"attrs\":\[{\"key\":\"foo\",\"value\":\"bar\"}\],\"pkg_path\":\"gno.land\/r\/demo\/foree\",\"func\":\"Foo\"},{\"type\":\"testing\",\"attrs\":\[{\"key\":\"foo\",\"value\":\"bar\"}\],\"pkg_path\":\"gno.land\/r\/demo\/foree\",\"func\":\"Foo\"},{\"type\":\"testing\",\"attrs\":\[{\"key\":\"foo\",\"value\":\"bar\"}\],\"pkg_path\":\"gno.land\/r\/demo\/foree\",\"func\":\"Foo\"},{\"type\":\"testing\",\"attrs\":\[{\"key\":\"foo\",\"value\":\"bar\"}\],\"pkg_path\":\"gno.land\/r\/demo\/foree\",\"func\":\"Foo\"},{\"type\":\"testing\",\"attrs\":\[{\"key\":\"foo\",\"value\":\"bar\"}\],\"pkg_path\":\"gno.land\/r\/demo\/foree\",\"func\":\"Foo\"},{\"type\":\"testing\",\"attrs\":\[{\"key\":\"foo\",\"value\":\"bar\"}\],\"pkg_path\":\"gno.land\/r\/demo\/foree\",\"func\":\"Foo\"},{\"type\":\"testing\",\"attrs\":\[{\"key\":\"foo\",\"value\":\"bar\"}\],\"pkg_path\":\"gno.land\/r\/demo\/foree\",\"func\":\"Foo\"},{\"type\":\"testing\",\"attrs\":\[{\"key\":\"foo\",\"value\":\"bar\"}\],\"pkg_path\":\"gno.land\/r\/demo\/foree\",\"func\":\"Foo\"}\]'
+stdout 'TX HASH: '
gnokey maketx call -pkgpath gno.land/r/demo/foree -func Bar -gas-fee 1000000ugnot -gas-wanted 2000000 -broadcast -chainid=tendermint_test test1
stdout OK!
@@ -17,7 +18,7 @@ stdout 'GAS WANTED: 2000000'
stdout 'GAS USED: [0-9]+'
stdout 'HEIGHT: [0-9]+'
stdout 'EVENTS: \[{\"type\":\"Foo\",\"attrs\":\[{\"key\":\"k1\",\"value\":\"v1\"},{\"key\":\"k2\",\"value\":\"v2\"}\],\"pkg_path\":\"gno.land\/r\/demo\/foree\",\"func\":\"subFoo\"},{\"type\":\"Bar\",\"attrs\":\[{\"key\":\"bar\",\"value\":\"baz\"}\],\"pkg_path\":\"gno.land\/r\/demo\/foree\",\"func\":\"subBar\"},{\"type\":\"Foo\",\"attrs\":\[{\"key\":\"k1\",\"value\":\"v1\"},{\"key\":\"k2\",\"value\":\"v2\"}\],\"pkg_path\":\"gno.land\/r\/demo\/foree\",\"func\":\"subFoo\"},{\"type\":\"Bar\",\"attrs\":\[{\"key\":\"bar\",\"value\":\"baz\"}\],\"pkg_path\":\"gno.land\/r\/demo\/foree\",\"func\":\"subBar\"}\]'
-
+stdout 'TX HASH: '
-- foree.gno --
diff --git a/gno.land/cmd/gnoland/testdata/event_normal.txtar b/gno.land/cmd/gnoland/testdata/event_normal.txtar
index b2792c07cf3..b2d6c01f3ec 100644
--- a/gno.land/cmd/gnoland/testdata/event_normal.txtar
+++ b/gno.land/cmd/gnoland/testdata/event_normal.txtar
@@ -10,6 +10,7 @@ stdout 'GAS WANTED: 2000000'
stdout 'GAS USED: \d+'
stdout 'HEIGHT: \d+'
stdout 'EVENTS: \[{\"type\":\"foo\",\"attrs\":\[{\"key\":\"key1\",\"value\":\"value1\"},{\"key\":\"key2\",\"value\":\"value2\"},{\"key\":\"key3\",\"value\":\"value3\"}\],\"pkg_path\":\"gno.land\/r\/demo\/ee\",\"func\":\"SubFoo\"},{\"type\":\"bar\",\"attrs\":\[{\"key\":\"bar\",\"value\":\"baz\"}\],\"pkg_path\":\"gno.land\/r\/demo\/ee\",\"func\":\"SubBar\"}\]'
+stdout 'TX HASH: '
gnokey maketx call -pkgpath gno.land/r/demo/ee -func Bar -gas-fee 1000000ugnot -gas-wanted 2000000 -broadcast -chainid=tendermint_test test1
stdout OK!
@@ -17,6 +18,7 @@ stdout 'GAS WANTED: 2000000'
stdout 'GAS USED: \d+'
stdout 'HEIGHT: \d+'
stdout 'EVENTS: \[{\"type\":\"bar\",\"attrs\":\[{\"key\":\"foo\",\"value\":\"bar\"}\],\"pkg_path\":\"gno.land/r/demo/ee\",\"func\":\"Bar\"}\]'
+stdout 'TX HASH: '
-- ee.gno --
package ee
diff --git a/gno.land/cmd/gnoland/testdata/run.txtar b/gno.land/cmd/gnoland/testdata/run.txtar
index 7246a10a1a4..f68346f09d6 100644
--- a/gno.land/cmd/gnoland/testdata/run.txtar
+++ b/gno.land/cmd/gnoland/testdata/run.txtar
@@ -11,6 +11,7 @@ stdout 'main: --- hello from foo ---'
stdout 'OK!'
stdout 'GAS WANTED: 200000'
stdout 'GAS USED: '
+stdout 'TX HASH: '
-- bar/bar.gno --
package bar
diff --git a/gno.land/pkg/integration/testdata/adduser.txtar b/gno.land/pkg/integration/testdata/adduser.txtar
index ebd0e4abb43..8c5706a68c4 100644
--- a/gno.land/pkg/integration/testdata/adduser.txtar
+++ b/gno.land/pkg/integration/testdata/adduser.txtar
@@ -14,6 +14,7 @@ stdout 'main: --- hello from foo ---'
stdout 'OK!'
stdout 'GAS WANTED: 200000'
stdout 'GAS USED: '
+stdout 'TX HASH: '
# should fail if user is added after node is started
! adduser test5
diff --git a/gno.land/pkg/integration/testdata/loadpkg_work.txtar b/gno.land/pkg/integration/testdata/loadpkg_work.txtar
index 5fb9a07c5de..e789c171dc2 100644
--- a/gno.land/pkg/integration/testdata/loadpkg_work.txtar
+++ b/gno.land/pkg/integration/testdata/loadpkg_work.txtar
@@ -12,6 +12,7 @@ stdout 'main: --- hello from foo ---'
stdout 'OK!'
stdout 'GAS WANTED: 200000'
stdout 'GAS USED: '
+stdout 'TX HASH: '
-- bar/bar.gno --
package bar
diff --git a/tm2/pkg/crypto/keys/client/broadcast.go b/tm2/pkg/crypto/keys/client/broadcast.go
index 70dafaaef90..1cf50bc32ed 100644
--- a/tm2/pkg/crypto/keys/client/broadcast.go
+++ b/tm2/pkg/crypto/keys/client/broadcast.go
@@ -2,6 +2,7 @@ package client
import (
"context"
+ "encoding/base64"
"flag"
"os"
@@ -79,6 +80,7 @@ func execBroadcast(cfg *BroadcastCfg, args []string, io commands.IO) error {
if res.CheckTx.IsErr() {
return errors.New("transaction failed %#v\nlog %s", res, res.CheckTx.Log)
} else if res.DeliverTx.IsErr() {
+ io.Println("TX HASH: ", base64.StdEncoding.EncodeToString(res.Hash))
return errors.New("transaction failed %#v\nlog %s", res, res.DeliverTx.Log)
} else {
io.Println(string(res.DeliverTx.Data))
@@ -87,6 +89,7 @@ func execBroadcast(cfg *BroadcastCfg, args []string, io commands.IO) error {
io.Println("GAS USED: ", res.DeliverTx.GasUsed)
io.Println("HEIGHT: ", res.Height)
io.Println("EVENTS: ", string(res.DeliverTx.EncodeEvents()))
+ io.Println("TX HASH: ", base64.StdEncoding.EncodeToString(res.Hash))
}
return nil
}
diff --git a/tm2/pkg/crypto/keys/client/maketx.go b/tm2/pkg/crypto/keys/client/maketx.go
index 2afccf9141c..7e67392ebe7 100644
--- a/tm2/pkg/crypto/keys/client/maketx.go
+++ b/tm2/pkg/crypto/keys/client/maketx.go
@@ -1,6 +1,7 @@
package client
import (
+ "encoding/base64"
"flag"
"fmt"
@@ -210,6 +211,7 @@ func ExecSignAndBroadcast(
return errors.Wrap(bres.CheckTx.Error, "check transaction failed: log:%s", bres.CheckTx.Log)
}
if bres.DeliverTx.IsErr() {
+ io.Println("TX HASH: ", base64.StdEncoding.EncodeToString(bres.Hash))
return errors.Wrap(bres.DeliverTx.Error, "deliver transaction failed: log:%s", bres.DeliverTx.Log)
}
@@ -219,6 +221,7 @@ func ExecSignAndBroadcast(
io.Println("GAS USED: ", bres.DeliverTx.GasUsed)
io.Println("HEIGHT: ", bres.Height)
io.Println("EVENTS: ", string(bres.DeliverTx.EncodeEvents()))
+ io.Println("TX HASH: ", base64.StdEncoding.EncodeToString(bres.Hash))
return nil
}
From fec2d18f630b44ccc2121472aa2284cd9c8caf6f Mon Sep 17 00:00:00 2001
From: sunspirit <167175638+linhpn99@users.noreply.github.com>
Date: Mon, 22 Jul 2024 16:26:58 +0700
Subject: [PATCH 2/2] fix(tm2): Fix request_id mismatch at http client (#2589)
It seems this check is not working as intended
The failing CI seems to be an existing issue not caused by these changes
Contributors' checklist...
- [ ] Added new tests, or not needed, or not feasible
- [ ] Provided an example (e.g. screenshot) to aid review or the PR is
self-explanatory
- [ ] Updated the official documentation or not needed
- [ ] No breaking changes were made, or a `BREAKING CHANGE: xxx` message
was included in the description
- [ ] Added references to related issues and PRs
- [ ] Provided any useful hints for running manual tests
- [ ] Added new benchmarks to [generated
graphs](https://gnoland.github.io/benchmarks), if any. More info
[here](https://github.com/gnolang/gno/blob/master/.benchmarks/README.md).
---------
Co-authored-by: Milos Zivkovic
---
tm2/pkg/bft/rpc/lib/client/http/client.go | 9 +-
.../bft/rpc/lib/client/http/client_test.go | 118 ++++++++++++------
2 files changed, 89 insertions(+), 38 deletions(-)
diff --git a/tm2/pkg/bft/rpc/lib/client/http/client.go b/tm2/pkg/bft/rpc/lib/client/http/client.go
index 290310cea31..aa4fc5c5392 100644
--- a/tm2/pkg/bft/rpc/lib/client/http/client.go
+++ b/tm2/pkg/bft/rpc/lib/client/http/client.go
@@ -18,6 +18,9 @@ const (
protoHTTP = "http"
protoHTTPS = "https"
protoTCP = "tcp"
+
+ portHTTP = "80"
+ portHTTPS = "443"
)
var (
@@ -57,7 +60,7 @@ func (c *Client) SendRequest(ctx context.Context, request types.RPCRequest) (*ty
}
// Make sure the ID matches
- if response.ID != response.ID {
+ if request.ID != response.ID {
return nil, ErrRequestResponseIDMismatch
}
@@ -230,9 +233,9 @@ func parseRemoteAddr(remoteAddr string) (string, string) {
if !strings.Contains(address, ":") {
switch protocol {
case protoHTTPS:
- address += ":443"
+ address += ":" + portHTTPS
case protoHTTP, protoTCP:
- address += ":80"
+ address += ":" + portHTTP
default: // noop
}
}
diff --git a/tm2/pkg/bft/rpc/lib/client/http/client_test.go b/tm2/pkg/bft/rpc/lib/client/http/client_test.go
index cfe69c3015c..4ccbfdc2d1e 100644
--- a/tm2/pkg/bft/rpc/lib/client/http/client_test.go
+++ b/tm2/pkg/bft/rpc/lib/client/http/client_test.go
@@ -108,53 +108,101 @@ func createTestServer(
func TestClient_SendRequest(t *testing.T) {
t.Parallel()
- var (
- request = types.RPCRequest{
- JSONRPC: "2.0",
- ID: types.JSONRPCStringID("id"),
- }
+ t.Run("valid request, response", func(t *testing.T) {
+ t.Parallel()
- handler = http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
- require.Equal(t, http.MethodPost, r.Method)
- require.Equal(t, "application/json", r.Header.Get("content-type"))
+ var (
+ request = types.RPCRequest{
+ JSONRPC: "2.0",
+ ID: types.JSONRPCStringID("id"),
+ }
- // Parse the message
- var req types.RPCRequest
- require.NoError(t, json.NewDecoder(r.Body).Decode(&req))
- require.Equal(t, request.ID.String(), req.ID.String())
+ handler = http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
+ require.Equal(t, http.MethodPost, r.Method)
+ require.Equal(t, "application/json", r.Header.Get("content-type"))
- // Send an empty response back
- response := types.RPCResponse{
+ // Parse the message
+ var req types.RPCRequest
+ require.NoError(t, json.NewDecoder(r.Body).Decode(&req))
+ require.Equal(t, request.ID.String(), req.ID.String())
+
+ // Send an empty response back
+ response := types.RPCResponse{
+ JSONRPC: "2.0",
+ ID: req.ID,
+ }
+
+ // Marshal the response
+ marshalledResponse, err := json.Marshal(response)
+ require.NoError(t, err)
+
+ _, err = w.Write(marshalledResponse)
+ require.NoError(t, err)
+ })
+
+ server = createTestServer(t, handler)
+ )
+
+ // Create the client
+ c, err := NewClient(server.URL)
+ require.NoError(t, err)
+
+ ctx, cancelFn := context.WithTimeout(context.Background(), time.Second*5)
+ defer cancelFn()
+
+ // Send the request
+ resp, err := c.SendRequest(ctx, request)
+ require.NoError(t, err)
+
+ assert.Equal(t, request.ID, resp.ID)
+ assert.Equal(t, request.JSONRPC, resp.JSONRPC)
+ assert.Nil(t, resp.Result)
+ assert.Nil(t, resp.Error)
+ })
+
+ t.Run("response ID mismatch", func(t *testing.T) {
+ t.Parallel()
+
+ var (
+ request = types.RPCRequest{
JSONRPC: "2.0",
- ID: req.ID,
+ ID: types.JSONRPCStringID("id"),
}
- // Marshal the response
- marshalledResponse, err := json.Marshal(response)
- require.NoError(t, err)
+ handler = http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
+ require.Equal(t, http.MethodPost, r.Method)
+ require.Equal(t, "application/json", r.Header.Get("content-type"))
- _, err = w.Write(marshalledResponse)
- require.NoError(t, err)
- })
+ // Send an empty response back,
+ // with an invalid ID
+ response := types.RPCResponse{
+ JSONRPC: "2.0",
+ ID: types.JSONRPCStringID("totally random ID"),
+ }
- server = createTestServer(t, handler)
- )
+ // Marshal the response
+ marshalledResponse, err := json.Marshal(response)
+ require.NoError(t, err)
- // Create the client
- c, err := NewClient(server.URL)
- require.NoError(t, err)
+ _, err = w.Write(marshalledResponse)
+ require.NoError(t, err)
+ })
- ctx, cancelFn := context.WithTimeout(context.Background(), time.Second*5)
- defer cancelFn()
+ server = createTestServer(t, handler)
+ )
- // Send the request
- resp, err := c.SendRequest(ctx, request)
- require.NoError(t, err)
+ // Create the client
+ c, err := NewClient(server.URL)
+ require.NoError(t, err)
- assert.Equal(t, request.ID, resp.ID)
- assert.Equal(t, request.JSONRPC, resp.JSONRPC)
- assert.Nil(t, resp.Result)
- assert.Nil(t, resp.Error)
+ ctx, cancelFn := context.WithTimeout(context.Background(), time.Second*5)
+ defer cancelFn()
+
+ // Send the request
+ resp, err := c.SendRequest(ctx, request)
+ assert.Nil(t, resp)
+ assert.ErrorIs(t, err, ErrRequestResponseIDMismatch)
+ })
}
func TestClient_SendBatchRequest(t *testing.T) {