• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 #region Copyright notice and license
2 
3 // Copyright 2018 The gRPC Authors
4 //
5 // Licensed under the Apache License, Version 2.0 (the "License");
6 // you may not use this file except in compliance with the License.
7 // You may obtain a copy of the License at
8 //
9 //     http://www.apache.org/licenses/LICENSE-2.0
10 //
11 // Unless required by applicable law or agreed to in writing, software
12 // distributed under the License is distributed on an "AS IS" BASIS,
13 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14 // See the License for the specific language governing permissions and
15 // limitations under the License.
16 
17 #endregion
18 
19 using System;
20 using System.Buffers;
21 using System.Collections.Generic;
22 using System.Linq;
23 using System.Runtime.InteropServices;
24 using Grpc.Core;
25 using Grpc.Core.Internal;
26 using Grpc.Core.Utils;
27 using NUnit.Framework;
28 
29 namespace Grpc.Core.Internal.Tests
30 {
31     // Converts IBufferReader into instances of ReadOnlySequence<byte>
32     // Objects representing the sequence segments are cached to decrease GC load.
33     public class ReusableSliceBufferTest
34     {
35         FakeBufferReaderManager fakeBufferReaderManager;
36 
37         [SetUp]
Init()38         public void Init()
39         {
40             fakeBufferReaderManager = new FakeBufferReaderManager();
41         }
42 
43         [TearDown]
Cleanup()44         public void Cleanup()
45         {
46             fakeBufferReaderManager.Dispose();
47         }
48 
49         [TestCase]
NullPayload()50         public void NullPayload()
51         {
52             var sliceBuffer = new ReusableSliceBuffer();
53             Assert.Throws(typeof(ArgumentNullException), () => sliceBuffer.PopulateFrom(fakeBufferReaderManager.CreateNullPayloadBufferReader()));
54         }
55 
56         [TestCase]
ZeroSegmentPayload()57         public void ZeroSegmentPayload()
58         {
59             var sliceBuffer = new ReusableSliceBuffer();
60             var sequence = sliceBuffer.PopulateFrom(fakeBufferReaderManager.CreateMultiSegmentBufferReader(new List<byte[]> {}));
61 
62             Assert.AreEqual(ReadOnlySequence<byte>.Empty, sequence);
63             Assert.IsTrue(sequence.IsEmpty);
64             Assert.IsTrue(sequence.IsSingleSegment);
65         }
66 
67         [TestCase]
SegmentsAreCached()68         public void SegmentsAreCached()
69         {
70             var bufferSegments1 = Enumerable.Range(0, 100).Select((_) => GetTestBuffer(50)).ToList();
71             var bufferSegments2 = Enumerable.Range(0, 100).Select((_) => GetTestBuffer(50)).ToList();
72 
73             var sliceBuffer = new ReusableSliceBuffer();
74 
75             var sequence1 = sliceBuffer.PopulateFrom(fakeBufferReaderManager.CreateMultiSegmentBufferReader(bufferSegments1));
76             var memoryManagers1 = GetMemoryManagersForSequenceSegments(sequence1);
77 
78             sliceBuffer.Invalidate();
79 
80             var sequence2 = sliceBuffer.PopulateFrom(fakeBufferReaderManager.CreateMultiSegmentBufferReader(bufferSegments2));
81             var memoryManagers2 = GetMemoryManagersForSequenceSegments(sequence2);
82 
83             // check memory managers are identical objects (i.e. they've been reused)
84             CollectionAssert.AreEquivalent(memoryManagers1, memoryManagers2);
85         }
86 
87         [TestCase]
MultiSegmentPayload_LotsOfSegments()88         public void MultiSegmentPayload_LotsOfSegments()
89         {
90             var bufferSegments = Enumerable.Range(0, ReusableSliceBuffer.MaxCachedSegments + 100).Select((_) => GetTestBuffer(10)).ToList();
91 
92             var sliceBuffer = new ReusableSliceBuffer();
93             var sequence = sliceBuffer.PopulateFrom(fakeBufferReaderManager.CreateMultiSegmentBufferReader(bufferSegments));
94 
95             int index = 0;
96             foreach (var memory in sequence)
97             {
98                 CollectionAssert.AreEqual(bufferSegments[index], memory.ToArray());
99                 index ++;
100             }
101         }
102 
103         [TestCase]
InvalidateMakesSequenceUnusable()104         public void InvalidateMakesSequenceUnusable()
105         {
106             var origBuffer = GetTestBuffer(100);
107 
108             var sliceBuffer = new ReusableSliceBuffer();
109             var sequence = sliceBuffer.PopulateFrom(fakeBufferReaderManager.CreateMultiSegmentBufferReader(new List<byte[]> { origBuffer }));
110 
111             Assert.AreEqual(origBuffer.Length, sequence.Length);
112 
113             sliceBuffer.Invalidate();
114 
115             // Invalidate with make the returned sequence completely unusable and broken, users must not use it beyond the deserializer functions.
116             Assert.Throws(typeof(ArgumentOutOfRangeException), () => { var first = sequence.First; });
117         }
118 
GetMemoryManagersForSequenceSegments(ReadOnlySequence<byte> sequence)119         private List<MemoryManager<byte>> GetMemoryManagersForSequenceSegments(ReadOnlySequence<byte> sequence)
120         {
121             var result = new List<MemoryManager<byte>>();
122             foreach (var memory in sequence)
123             {
124                 Assert.IsTrue(MemoryMarshal.TryGetMemoryManager(memory, out MemoryManager<byte> memoryManager));
125                 result.Add(memoryManager);
126             }
127             return result;
128         }
129 
GetTestBuffer(int length)130         private byte[] GetTestBuffer(int length)
131         {
132             var testBuffer = new byte[length];
133             for (int i = 0; i < testBuffer.Length; i++)
134             {
135                 testBuffer[i] = (byte) i;
136             }
137             return testBuffer;
138         }
139     }
140 }
141