Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

test: Add a test for decompression exceeding max receive message size #7938

Merged
merged 5 commits into from
Dec 23, 2024
Merged
Changes from 2 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
67 changes: 67 additions & 0 deletions test/compressor_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -785,3 +785,70 @@ func (s) TestGzipBadChecksum(t *testing.T) {
t.Errorf("ss.Client.UnaryCall(_) = _, %v\n\twant: _, status(codes.Internal, contains %q)", err, gzip.ErrChecksum)
}
}

// fakeCompressor returns a messages of a configured size, irrespective of the
// input.
type fakeCompressor struct {
decompressedMessageSize int
}

func (f *fakeCompressor) Compress(w io.Writer) (io.WriteCloser, error) {
return nopWriteCloser{w}, nil
}

func (f *fakeCompressor) Decompress(io.Reader) (io.Reader, error) {
return bytes.NewReader(make([]byte, f.decompressedMessageSize)), nil
}

func (f *fakeCompressor) Name() string {
// Use the name of an existing compressor to avoid interactions with other
// tests since compressors can't be un-registered.
return "gzip"
Comment on lines +804 to +806
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Can we use t.Name as the name for the compressor and thereby avoid interactions with other tests?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I tried this earlier, but the clients in the following test pick up the registered compressor and start failing.

func (s) TestClientSupportedCompressors(t *testing.T) {

There's no way to unregister a compressor presently. There is a deprecated WithCompressor that allows using a compressor without registration that I can use.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Do you mind filing an issue for us to think about how we can handle this. It is not ideal for one test to influence every test that comes after it.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Opened #7960.

}

type nopWriteCloser struct {
io.Writer
}

func (nopWriteCloser) Close() error {
return nil
}

// TestDecompressionExceedsMaxMessageSize uses a fake compressor that produces
// messages of size 100 bytes on decompression. A server is started with the
// max receive message size restricted to 99 bytes. The test verifies that the
// client receives a ResourceExhausted response from the server.
func (s) TestDecompressionExceedsMaxMessageSize(t *testing.T) {
oldC := encoding.GetCompressor("gzip")
defer func() {
encoding.RegisterCompressor(oldC)
}()
messageLen := 100
easwars marked this conversation as resolved.
Show resolved Hide resolved
encoding.RegisterCompressor(&fakeCompressor{decompressedMessageSize: messageLen})
ss := &stubserver.StubServer{
UnaryCallF: func(context.Context, *testpb.SimpleRequest) (*testpb.SimpleResponse, error) {
return &testpb.SimpleResponse{}, nil
},
}
if err := ss.Start([]grpc.ServerOption{grpc.MaxRecvMsgSize(messageLen - 1)}); err != nil {
t.Fatalf("Error starting endpoint server: %v", err)
}
defer ss.Stop()

ctx, cancel := context.WithTimeout(context.Background(), defaultTestTimeout)
defer cancel()

p, err := newPayload(testpb.PayloadType_COMPRESSABLE, int32(50))
if err != nil {
t.Fatalf("Unexpected error from newPayload: %v", err)
}
easwars marked this conversation as resolved.
Show resolved Hide resolved
req := &testpb.SimpleRequest{Payload: p}
_, err = ss.Client.UnaryCall(ctx, req, grpc.UseCompressor("gzip"))
if err == nil {
t.Errorf("Client.UnaryCall(%+v) = nil, want %v", req, codes.ResourceExhausted)
}
easwars marked this conversation as resolved.
Show resolved Hide resolved

if got, want := status.Code(err), codes.ResourceExhausted; got != want {
t.Errorf("Client.UnaryCall(%+v) returned stats %v, want %v", req, got, want)
easwars marked this conversation as resolved.
Show resolved Hide resolved
}
}
Loading