Skip to content

Commit

Permalink
roachtest: make follower-reads test use protobuf encoded requests
Browse files Browse the repository at this point in the history
Previously, the roachtest for
`follower-reads/mixed-version/single-region` used JSON encoding for the
`ts/query` endpoint. This caused the client to send the newly updated
`timerseries` proto to an older cluster in JSON format. Although this
was defined as an `optional` field in the proto, since it was encoded in
JSON, that information was lost over the wire.

In other places, such as DBConsole, we expect the client to be sending
protobuf encoded messages and not JSON. In the same way, roachtests
(another client) should do the same. When this message is sent as a
protobuf, the `optional` tag of the field is encoded in the message and
the server is able to process is it as such.

There are related links in the issue:
#99117.

Fixes #99117.

Release note: None
  • Loading branch information
aadityasondhi committed Mar 23, 2023
1 parent 1e2ea17 commit b0659ec
Show file tree
Hide file tree
Showing 2 changed files with 38 additions and 1 deletion.
2 changes: 1 addition & 1 deletion pkg/cmd/roachtest/tests/follower_reads.go
Original file line number Diff line number Diff line change
Expand Up @@ -730,7 +730,7 @@ func verifyHighFollowerReadRatios(
}

var response tspb.TimeSeriesQueryResponse
if err := httputil.PostJSON(http.Client{}, url, &request, &response); err != nil {
if err := httputil.PostProtobuf(ctx, http.Client{}, url, &request, &response); err != nil {
t.Fatal(err)
}

Expand Down
37 changes: 37 additions & 0 deletions pkg/util/httputil/http.go
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@ package httputil

import (
"bytes"
"context"
"io"
"net/http"
"strconv"
Expand Down Expand Up @@ -110,6 +111,42 @@ func PostJSONWithRequest(
return doJSONRequest(httpClient, req, response)
}

// PostProtobuf uses the supplied client to POST request to the URL specified by
// the parameters and unmarshal the result into response, using a
// protobuf-encoded request body.
func PostProtobuf(
ctx context.Context, httpClient http.Client, path string, request, response protoutil.Message,
) error {
buf, err := protoutil.Marshal(request)
if err != nil {
return err
}
reader := bytes.NewReader(buf)
req, err := http.NewRequestWithContext(ctx, "POST", path, reader)
if err != nil {
return err
}
if timeout := httpClient.Timeout; timeout > 0 {
req.Header.Set("Grpc-Timeout", strconv.FormatInt(timeout.Nanoseconds(), 10)+"n")
}
req.Header.Set(AcceptHeader, ProtoContentType)
req.Header.Set(ContentTypeHeader, ProtoContentType)
resp, err := httpClient.Do(req)
if err != nil {
return err
}
defer resp.Body.Close()
b, err := io.ReadAll(resp.Body)
if contentType := resp.Header.Get(ContentTypeHeader); !(resp.StatusCode == http.StatusOK && contentType == ProtoContentType) {
// NB: errors.Wrapf(nil, ...) returns nil.
// nolint:errwrap
return errors.Errorf(
"status: %s, content-type: %s, body: %s, error: %v", resp.Status, contentType, b, err,
)
}
return protoutil.Unmarshal(b, response)
}

func doJSONRequest(
httpClient http.Client, req *http.Request, response protoutil.Message,
) (*http.Response, error) {
Expand Down

0 comments on commit b0659ec

Please sign in to comment.