| /* |
| * |
| * Copyright 2026 gRPC authors. |
| * |
| * Licensed under the Apache License, Version 2.0 (the "License"); |
| * you may not use this file except in compliance with the License. |
| * You may obtain a copy of the License at |
| * |
| * http://www.apache.org/licenses/LICENSE-2.0 |
| * |
| * Unless required by applicable law or agreed to in writing, software |
| * distributed under the License is distributed on an "AS IS" BASIS, |
| * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
| * See the License for the specific language governing permissions and |
| * limitations under the License. |
| * |
| */ |
| |
| package mem_test |
| |
| import ( |
| "testing" |
| "unsafe" |
| |
| "google.golang.org/grpc/internal/grpctest" |
| "google.golang.org/grpc/internal/mem" |
| ) |
| |
| type s struct { |
| grpctest.Tester |
| } |
| |
| func Test(t *testing.T) { |
| grpctest.RunSubTests(t, s{}) |
| } |
| |
| func (s) TestBufferPool_Clears(t *testing.T) { |
| poolConfigs := []struct { |
| name string |
| factory func() (*mem.BinaryTieredBufferPool, error) |
| wantCleared bool |
| bufferSize int |
| }{ |
| { |
| name: "regular_sized", |
| factory: func() (*mem.BinaryTieredBufferPool, error) { |
| return mem.NewBinaryTieredBufferPool(3) // 8 bytes |
| }, |
| bufferSize: 8, |
| wantCleared: true, |
| }, |
| { |
| name: "regular_fallback", |
| factory: func() (*mem.BinaryTieredBufferPool, error) { |
| return mem.NewBinaryTieredBufferPool(3) |
| }, |
| bufferSize: 10, |
| wantCleared: true, |
| }, |
| { |
| name: "dirty_sized", |
| factory: func() (*mem.BinaryTieredBufferPool, error) { |
| return mem.NewDirtyBinaryTieredBufferPool(3) |
| }, |
| bufferSize: 8, |
| wantCleared: false, |
| }, |
| { |
| name: "dirty_fallback", |
| factory: func() (*mem.BinaryTieredBufferPool, error) { |
| return mem.NewDirtyBinaryTieredBufferPool(3) |
| }, |
| bufferSize: 10, |
| wantCleared: false, |
| }, |
| } |
| |
| for _, tc := range poolConfigs { |
| t.Run(tc.name, func(t *testing.T) { |
| pool, err := tc.factory() |
| if err != nil { |
| t.Fatalf("Failed to create pool: %v", err) |
| } |
| |
| for { |
| buf1 := pool.Get(tc.bufferSize) |
| // Mark the buffer with data. |
| for i := range *buf1 { |
| (*buf1)[i] = 0xAA |
| } |
| pool.Put(buf1) |
| |
| buf2 := pool.Get(tc.bufferSize) |
| // Check if we got the same underlying array. |
| if unsafe.SliceData(*buf1) != unsafe.SliceData(*buf2) { |
| pool.Put(buf2) |
| continue |
| } |
| |
| // We have a reused buffer. Check if it's cleared. |
| gotCleared := true |
| for _, b := range *buf2 { |
| if b != 0 { |
| gotCleared = false |
| break |
| } |
| } |
| |
| if tc.wantCleared != gotCleared { |
| t.Fatalf("buffer cleared state mismatch: want %t, got %v", tc.wantCleared, gotCleared) |
| } |
| |
| pool.Put(buf2) |
| break |
| } |
| }) |
| } |
| } |